using System; 

namespace DelegateTest {
    /// <summary> 委托类型表示对具有特定参数列表和返回类型的方法的引用
    /// 通过委托， 可以将方法视为可以分配并且作为参数传递的实体。
    /// 委托还类似于其他一些语言中存在的 "函数指针"
    /// 与函数指针不同， 委托是面向对象并且类型安全的。
    delegate double Function(double x);

    class Multiplier {
        double _factor;

        public Multiplier(double factor) => _factor = factor;

        public double Multiply(double x) => x * _factor;
    }

    public class DelegateExample {

        static double[] Apply(double[] a, Function f) {
            var result = new double[a.Length];
            for(int i=0; i<a.Length; i++){
                result[i] = f(a[i]);
            }
            return result;
        }

        public static void test(){
            double[] a = {0.0, 0.5, 1.0};

            double[] squares = Apply(a, (x)=>x*x);
            Console.WriteLine("delegate x*x, then squares is :");
            for(int i=0; i<squares.Length; i++){
                Console.Write(squares[i] + "\t");
            }
            Console.WriteLine("\n");

            double[] sines = Apply(a, Math.Sin);
            Console.WriteLine("delegate Math.Sin, then sines is :");
            for(int i=0; i<sines.Length; i++){
                Console.Write(sines[i] + "\t");
            }
            Console.WriteLine("\n");
            
            Multiplier m = new Multiplier(2.0);
            double[] doubles = Apply(a, m.Multiply);
            Console.WriteLine("delegate Multiplier(2.0), then doubles is :");
            for(int i=0; i<doubles.Length; i++){
                Console.Write(doubles[i] + "\t");
            }
            Console.WriteLine("\n");
        }
    }
}